Skip to content

kernel: define SUPPORT_PRAGMA_UNUSED for clang - #619

Closed
cyclistmass wants to merge 1 commit into
Clozure:masterfrom
cyclistmass:kernel-three
Closed

cyclistmass wants to merge 1 commit into
Clozure:masterfrom
cyclistmass:kernel-three

Conversation

@cyclistmass

@cyclistmass cyclistmass commented Aug 27, 2026 •

Copy link
Copy Markdown
Contributor

SUPPORT_PRAGMA_UNUSED guards ten #pragma unused(...) annotations in the three *-exceptions.c files. Nothing in the tree defines it, so no compiler has ever seen those annotations.

This patch defines it in lisp.h for clang only.

gcc 11.5.0 clang 15.0.7
Recognizes #pragma unused no, one -Wunknown-pragmas per site yes
Removes the unused parameter warning no yes

An unconditional define would add ten gcc warnings and remove none. On arm64-exceptions.c, clang goes from 19 to 13 unused parameter warnings, and each of the six that disappear is a parameter that a pragma names. The object file md5 does not change on either compiler, so the patch changes diagnostics and nothing else.

I compiled only arm64-exceptions.c. I read the other seven sites and did not compile them.

The commit message has the full measurement and its control.

@cyclistmass
cyclistmass changed the base branch from arm64 to master September 9, 2026 03:59
@xrme

xrme commented Sep 25, 2026

Copy link
Copy Markdown
Member

The recursive_lock_trylock issue #597 was fixed in b5a00d1

…piler that implements it

SUPPORT_PRAGMA_UNUSED is #ifdef'd in ten places and #define'd in none, so the
`#pragma unused(...)' annotations it guards have never reached any compiler:

    $ git grep -c SUPPORT_PRAGMA_UNUSED -- 'lisp-kernel/*.c'
    lisp-kernel/arm-exceptions.c          (936, 1002, 1305)
    lisp-kernel/arm64-exceptions.c        (1114, 1196, 1825)
    lisp-kernel/ppc-exceptions.c          (983, 1146, 1367, 1540)
    $ git grep -n 'define[[:space:]]*SUPPORT_PRAGMA_UNUSED'
    (nothing)

Each site says that a parameter forced on the function by a handler-dispatch
signature is deliberately unused -- do_hard_stack_overflow needs only xp,
do_spurious_wp_fault needs none of the three, allocate_no_stack needs none.  The
intent is right and recorded; only the channel to the compiler is dead.

=== MEASURED, because #pragma unused is not a thing to reason about from memory

It is a Metrowerks/MPW-lineage extension and gcc and clang do not agree about
it.  So it was measured rather than recalled, on the real do_hard_stack_overflow
shape, with a positive control (the same file WITHOUT the pragma, which must
emit `unused parameter' before any other result is interpretable).  gcc 11.5.0
20240719 on x86_64 and aarch64, clang 15.0.7 on aarch64:

                                    gcc 11.5.0            clang 15.0.7
  recognised?                       NO                    YES
                                    "ignoring '#pragma    (no diagnostic
                                     unused ' [-Wunknown-  at all)
                                     pragmas]"
  suppresses `unused parameter'?    NO   (still 2)        YES  (2 -> 0)
  diagnostics added                 1 per site            0
  -Wall -Wextra -Werror exit code   1 (2 errors -> 3)     0

Verbatim, gcc, with the pragma present:

    B.c: In function 'do_hard_stack_overflow':
    B.c: warning: ignoring '#pragma unused ' [-Wunknown-pragmas]
    B.c:53: warning: unused parameter 'area' [-Wunused-parameter]
    B.c:67: warning: unused parameter 'addr' [-Wunused-parameter]
    exit code: 0

Verbatim, clang, same file, same flags: no output, exit 0.

So an UNCONDITIONAL #define would be measurably worse than the dead guard: on
gcc it suppresses nothing and adds one -Wunknown-pragmas at each of the ten
sites, and turns a -Wall -Wextra -Werror build from 2 errors into 3.  Hence
clang only.

Two more measurements that bear on the risk, both on clang 15.0.7:

  * A pragma naming an identifier that does not exist is DIAGNOSED, not ignored:
    "undeclared variable 'x' used as an argument for '#pragma unused'
    [-Wignored-pragmas]".  clang parses the argument list, so these annotations
    stay honest as the code changes -- something -Wno-unused-parameter cannot
    do.
  * A pragma naming a parameter that IS used is silently accepted: no
    diagnostic, exit 0 even under -Werror.
  * At file scope the names are not in scope and clang warns twice and
    suppresses nothing.  All ten sites are inside a function body, which is
    where it works.

=== Where the #define goes

lisp.h, because all three files include it first and this is a property of the
COMPILER, not of a platform -- putting it in the per-platform headers would mean
repeating a __clang__ test in each of them.

=== Relationship to -Wno-unused-parameter on the arm64 kernel

I added -Wno-unused-parameter to lisp-kernel/linuxarm64/Makefile in a separate
arm64 patch, and said there that what to do with the #pragma blocks was your
call.  This is that follow-up, and it does NOT make the flag redundant:
linuxarm64/Makefile:11 is `CC = ${CROSS}gcc', so on our own kernel build this
patch changes nothing at all and the flag is still what suppresses the 78
-Wunused-parameter there.  Measured, not assumed -- see below, where gcc's
warning census is bit-for-bit the same with and without this patch.  The two are
complementary: the pragma covers the compiler that understands it, the flag
covers the one that does not.

=== The alternative, if you would rather not

Delete the ten #ifdef/#pragma/#endif blocks and keep warning suppression at the
build flags.  That is a defensible call and a smaller thing to maintain; it just
throws away suppression that measurably works on clang, and clang is the
compiler the Darwin targets use.  I have written the version I think is right;
either is easy from here and it is your tree.

=== NOT TESTED

⛔ Of the three files this affects, only arm64-exceptions.c has been compiled.

RED-then-GREEN on the real translation unit, aarch64, tree at the pin:
lisp-kernel/arm64-exceptions.c, -Wall -Wextra, otherwise the Makefile's own
flags (-include ../platform-linuxarm64.h -DLINUX -DARM64 ... -g -O2 -Wno-format).
Three configurations, because the third is the one that justifies "clang only":

                          unused-param  -Wunknown-pragmas  total warn   .o md5
  RED     gcc,   no macro       19              0              61       96930241
  GREEN   gcc,   no macro       19              0              61       96930241
  COUNTER gcc,   macro ON       19              3              64       96930241
  RED     clang, no macro       19              0              23       7d5242da
  GREEN   clang, macro ON       13              0              17       7d5242da

  * clang 19 -> 13.  Grouped by parameter name, so that "six warnings went
    away" cannot be six DIFFERENT warnings:

        addr 4->2   area 2->0   size 1->0   xp 4->3
        info 1->1   instruction 1->1   param 1->1   signum 1->1   tcr 4->4

    Total -6, and the three #pragma lines in the file name exactly six
    identifiers: (area,addr) + (xp,area,addr) + (size) = 2+3+1.  Every
    parameter NOT named by a pragma is untouched.
  * ZERO -Wignored-pragmas on the green clang run -- the check that every
    identifier the three pragmas name really is in scope.
  * gcc RED vs GREEN is BYTE-IDENTICAL output, because __clang__ is not
    defined and the guard stays false.  The -Wno-unused-parameter flag
    therefore still does all the work on our own kernel build.
  * COUNTER is what an unconditional #define would do to gcc: three
    -Wunknown-pragmas, one per site, 61 -> 64 warnings, and not one
    unused-parameter removed.  Worse than the dead guard, measured rather than
    predicted.
  * THE .o md5 IS IDENTICAL in all three gcc configurations and in both clang
    configurations.  So this changes diagnostics and provably nothing else --
    no generated code moves, on either compiler, with or without the macro.
  * Positive control: the RED clang run emitted 19 > 0, i.e. the instrument was
    seen reporting the un-suppressed state before the suppressed one was
    believed.
  * Reproduced on a second, independent pin tree by a red/green control
    script that carries these gates.

NOT COMPILED, at all: arm-exceptions.c (ARM32) and ppc-exceptions.c -- I have no
ARM32 or PPC machine.  Their seven sites were READ, and every identifier named
there is a parameter of the enclosing function, so I expect the same result --
but that is inspection, not a build.

Confidence: high that the #define is correct for clang and inert for gcc (red
and green both watched, on the real TU); high that it is a no-op for our own
kernel build; medium that the seven un-compiled sites are clean, on inspection
alone.

Signed-off-by: Mauro DiBenedetto <maurodibenedetto@gmail.com>
@cyclistmass cyclistmass changed the title kernel: three C fixes kernel: define SUPPORT_PRAGMA_UNUSED for clang Sep 29, 2026
@cyclistmass

Copy link
Copy Markdown
Contributor Author

Thank you. I have rebased this onto master and dropped two of the three commits, so what is left is one change.

recursive_lock_trylock: b5a00d1 is this patch, line for line, so I dropped ours rather than ask you to read it twice.

The albt.c backtrace fix is also open as #643, which I raised later as a single commit. The two are byte-identical. I dropped it here, so #643 is the one to read.

What remains is the SUPPORT_PRAGMA_UNUSED define. I have retitled the PR and cut the description down to that one change. The measurement and its control are unchanged, and so is the boundary I put on them: I compiled the arm64 shape rather than all ten sites.

@xrme

xrme commented Oct 2, 2026

Copy link
Copy Markdown
Member

Committed as 89e1b3f. Thank you.

@xrme xrme closed this Oct 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants